/**
  ******************************************************************************
  * File Name          : MODBUS protocol
  * Auther             : xifeng.yao@qq.com
  * Description        : Code for modbus applications
  ******************************************************************************
  * @attention
  * 整合3种Modbus数据格式： MODBUS-RTU    MODBUS-TCP    MODBUS-ASCII
  * 对应3个接口函数：
  *
  * @Modbus_RTU:    bool API_ModbusRTU_Slave_Analy(char* protocoldata,  uint16_t* Length);
  * 
  * @Modbus_TCP:    bool API_ModbusTCP_Slave_Analy(char* protocoldata,  uint16_t* Length);
  * 
  * @Modbus_ASCII:  bool API_ModbusASCII_Slave_Analy(char* protocoldata,  uint16_t* Length);
  *   
  ********/
	
/* Includes ------------------------------------------------------------------*/
#include <string.h>

#include "litemodbus.h"
#include "litemodbusBase.h"
#include "litemodbusCrc.h"


/**
  * @brief  Modbus 0x01 0x02 0x05 0x0f 协议解析 
  * @param  *response    指向数据帧，帧头
             int_value   0x01,0x02 读协议，需要应答的数据 
            *ext_value   0x05,0x0f 写协议，需要返回的数据 
  * @retval true=需要写入变量操作
            false=不需要写入操作            
  */
bool Modbus_Coils_Addr_Analy(uint8_t* response, int int_value, void* ext_value)
{
  ModbusFormat* dataptr = (ModbusFormat*)response;
//  char*     output = ext_value;
  uint16_t  index = HSB2LSB(dataptr->value, 16);
  
  /*根据 命令码 解析*/
  switch(dataptr->cmd)
  {
    case  CMD_RX_COILS:    //0x01  读线圈寄存器
    case  CMD_RX_DISCRETE: //0x02  读离散输入寄存器
                          /*写入应答帧 0 or 1*/
                          if(int_value)   
                          {dataptr->data[dataptr->len/8] |= 1<<(dataptr->len%8);}
                          else            
                          {dataptr->data[dataptr->len/8] &= ~(1<<(dataptr->len%8));}
                          
                          if(index <= ++dataptr->len) //bit位数+1
                          { /*载入bit数据完成，开始组应答包*/
                            dataptr->len = 1 + (dataptr->len -1)/8; //bit位数转字节数
                            memcpy(&response[2], &dataptr->len, dataptr->len+1); //将bit数据前移应答帧
                            return true; 
                          }
                          break;
                          
    case  CMD_TX_COIL:   //0x05  写单个线圈寄存器
                         *(char*)ext_value = index ? 1: 0;  //*resp_len = 8;
                         return  true;
                         
    case  CMD_TX_COILS:  //0x0f  写多个线圈寄存器
                         *(char*)ext_value = (dataptr->data[dataptr->len/8] & (0x01<<(dataptr->len%8))) ? 1: 0;
                         if(index <= ++dataptr->len) //bit位数+1
                         { return true; }
                         break;
                         
      default:           ERR_CMD(response)
                         return true;
  }
  return false; //未解析完成，不转应答流程
}

/**
  * @brief  Modbus 0x03 0x04 0x06 0x10 协议解析 
  * @param  *response    指向数据帧，帧头
             int_value   0x03,0x04 读协议，需要应答的数据 
            *ext_value   0x06,0x10 写协议，需要返回的数据 
  * @retval true=需要写入变量操作
            false=不需要写入操作            
  */
bool Modbus_Hold_Addr_Analy(uint8_t* response, int int_value, void* ext_value)
{
  ModbusFormat* dataptr = (ModbusFormat*)response;
  char*     output = ext_value;
  uint16_t  index = HSB2LSB(dataptr->value, 16);
  
  /*根据 命令码 解析*/
  switch(dataptr->cmd)
  {
    case  CMD_RX_HOLDREG:  //0x03  读保持寄存器
    case  CMD_RX_INPUTREG: //0x04  读输入寄存器
                          dataptr->data[dataptr->len++] = (int_value>>8)&0x0FF; 
                          dataptr->data[dataptr->len++] = int_value&0x0FF; 
    
                          if(index*2 <= dataptr->len)
                          { /*载入bit数据完成，开始组应答包*/
                            memcpy(&response[2], &dataptr->len, dataptr->len+1); //将bytes数据前移应答帧
                            return true; 
                          } 
                          break;
                          
    case  CMD_TX_HOLDREG: //0x06  写单个保持寄存器
                         output[0] = dataptr->value[1];  output[1] = dataptr->value[0];
                         return true;
    
    case  CMD_TX_HOLDREGS: //0x10  写多个保持寄存器
                         output[1] = dataptr->data[dataptr->len];
                         output[0] = dataptr->data[dataptr->len + 1];  dataptr->len += 2; 
    
                         if(index*2 <= dataptr->len)
                         {return true;} 
                         break;
    
      default:           ERR_CMD(response)
                         return 0x80;
  }
  return false; //未解析完成，不转应答流程
}


